const socketIO = require('socket.io');
const {getNewMessageCount, getChatList, getMessageList, findUser, addNewMessage, updateNewMessage, getRankingList, checkUserIsFree, createMath, giveUpChallenge, saveMatchData, matchDraw, admitDefeat} = require('../service/userService');

//自定义socket处理程序类
class CustomSocket {
    constructor(server) {
        this.server = server;
        this.io = socketIO(server, {
            allowEIO3: true,
            cors: {//跨域
                origin: ['http://192.168.1.11:8080', 'http://192.168.0.46:8080'],
                methods: ['GET', 'POST'],
                credentials: true
            }
        });
        //用户对象
        this.userListObject = {};
        this.handleEvent();
    }

    //处理事件
    handleEvent() {
        //监听客户端连接
        this.io.on('connection', async (socket) => {
            let currentUserId = 0;//当前用户id
            //监听用户登录
            socket.on('login', async (data) => {
                currentUserId = data.id;
                this.addToUserListObject(data.id, socket);
            });
            //监听用户登出
            socket.on('logout', () => {
                this.removeFromUserListObject(currentUserId, socket);
            });
            //监听获取新消息数事件
            socket.on('getNewMessageCount', async () => {
                //获取新消息数
                await CustomSocket.getNewMessageCount(currentUserId, socket);
            });
            //监听获取聊天列表事件
            socket.on('getChatList', async () => {
                await CustomSocket.getChatList(currentUserId, socket);
            });
            //获取与指定用户的聊天记录
            socket.on('getMessageList', async (userId) => {
                socket['isChat'] = true;//是否在聊天框
                const data = await getMessageList(currentUserId, userId, 0);
                socket.emit('messageList', data);

                //通知用户更新新消息数和聊天列表
                await CustomSocket.getNewMessageCount(currentUserId, socket);
                await CustomSocket.getChatList(currentUserId, socket);
                //通知对方我已读消息
                await this.messageIsRead(currentUserId, userId);
            });
            //获取下一段聊天记录
            socket.on('getNextMessageList', async (userId, offset) => {
                const data = await getMessageList(currentUserId, userId, offset);
                socket.emit('nextMessageList', data);
            });
            //监听获取当前用户信息
            socket.on('getUserInfo', async (userId) => {
                const data = await findUser({id: userId});
                socket.emit('userInfo', data);
            });
            //监听获取自己的信息
            socket.on('getOwnUserInfo', async () => {
                const data = await findUser({id: currentUserId});
                socket.emit('ownUserInfo', data);
            });
            //发送消息
            socket.on('sendMessage', async (data) => {
                data['fromUserId'] = currentUserId;
                const result = await addNewMessage(data);
                //socket.emit('successAddMessage', result);
                //通知用户更新聊天列表
                //await CustomSocket.getChatList(currentUserId, socket);
                await this.sendToOther(currentUserId, socket, result);
                //发送消息给对方
                await this.sendMessageToOther(currentUserId, data['toUserId'], result.data);
            });
            //通知对方成功接收消息
            socket.on('notifyAcceptSuccess', async (data) => {
                //更新消息为已读
                await updateNewMessage({fromUserId: data['toUserId'], toUserId: currentUserId});
                //更新新消息数和聊天列表
                await CustomSocket.getNewMessageCount(currentUserId, socket);
                await CustomSocket.getChatList(currentUserId, socket);
                //通知对方已接收消息
                await this.messageIsRead(currentUserId, data['toUserId']);
            });
            //监听用户是否进入聊天
            socket.on('isChat', async () => {
                socket['isChat'] = true;//是否在聊天框
            });
            //监听用户是否离开聊天框
            socket.on('leaveChat', async () => {
                socket['isChat'] = false;//是否在聊天框
            });
            //获取排行榜
            socket.on('getRankingList', async () => {
                const server = this.server;
                const data = await getRankingList();
                socket.emit('rankingList', data);
            });
            //监听用户发起挑战
            socket.on('sendChallenge', async (id) => {
                const isOnline = await this.isOnline(id);
                if (isOnline && isOnline.length > 0) {
                    const check = await checkUserIsFree(id);
                    if (check.code === 1) {
                        isOnline.forEach((item) => {
                            item.emit('getChallenge', currentUserId);
                        });
                    } else {
                        socket.emit('challengeResult', {code: 0, msg: check.msg});
                    }
                } else {
                    socket.emit('challengeResult', {code: 0, msg: '您挑战的用户不在线'});
                }
            });
            //用户接受挑战
            socket.on('acceptChallenge', async (data) => {
                const result = await createMath({initiatorId: data.toUserId, recipientId: currentUserId});
                if (result.code === 1) {
                    await this.acceptChallenge(data);
                } else {
                    await this.rejectChallenge(result);
                }
                socket.emit('createMath', result);
            });
            //用户拒绝挑战
            socket.on('rejectChallenge', async (data) => {
                await this.rejectChallenge(data);
            });
            //查询用户是否有未完成的比赛
            socket.on('checkMatch', async () => {
                const check = await checkUserIsFree(currentUserId);
                socket.emit('checkMatch', check);
            });
            //放弃比赛
            socket.on('giveUpChallenge', async () => {
                await giveUpChallenge(currentUserId);
                socket.emit('giveUpChallenge');
            });
            //监听棋子数据发送
            socket.on('sendChessData', async (data) => {
                data['currentUserId'] = currentUserId;
                const saveResult = await saveMatchData(data);
                if (saveResult.code === 1) {
                    await this.acceptChessData(data);
                }
                saveResult['isFinish'] = data.isFinish;
                socket.emit('saveChessDataResult', saveResult);
            });
            //监听平局
            socket.on('draw', async (data) => {
                await matchDraw(data);
                //await this.sendMessage(data['toUserId'], 'draw');
            });
            //监听主动认输
            socket.on('admitDefeat', async (data) => {
                data['currentUserId'] = currentUserId;
                const result = await admitDefeat(data);
                if (result.code === 1) {
                    await this.sendMessage(data['toUserId'], 'acceptAdmitDefeat');
                }
                socket.emit('admitDefeatResult', result);
            });
            //申请和棋
            socket.on('applyDraw', async (data) => {
                await this.sendMessage(data['toUserId'], 'applyDraw', {userId: currentUserId});
            });
            //监听是否同意和棋
            socket.on('applyDrawResult', async (data) => {
                if (data.agree) {
                    const result = await matchDraw(data);
                    if (result.code === 1) {
                        await this.sendMessage(data['toUserId'], 'acceptApplyDrawResult', data);
                    }
                    socket.emit('saveApplyDrawResult', result);
                } else {
                    await this.sendMessage(data['toUserId'], 'acceptApplyDrawResult', data);
                }
            });
            //检查在线用户
            socket.on('checkOnlineUser', async () => {
                let result = Object.keys(this.userListObject);
                socket.emit('checkOnlineUser', result);
            });
            //监听客户端断开连接
            socket.on('disconnect', () => {
                this.removeFromUserListObject(currentUserId, socket);
            });
        });
    }

    //发送在线、离线消息
    checkOnlineUser(socket) {
        let result = Object.keys(this.userListObject);
        socket.broadcast.emit('checkOnlineUser', result);
    }

    //发送拒绝挑战的信息
    async rejectChallenge(data) {
        const list = this.userListObject[data.toUserId];
        //如果对方在线则发送
        if (list && list.length > 0) {
            for (let i = 0; i < list.length; i++) {
                list[i].emit('challengeResult', {code: 0, msg: data.msg});
            }
        }
    }

    //发送接受挑战的信息
    async acceptChallenge(data) {
        const list = this.userListObject[data.toUserId];
        //如果对方在线则发送
        if (list && list.length > 0) {
            for (let i = 0; i < list.length; i++) {
                list[i].emit('challengeResult', {code: 1, msg: ''});
            }
        }
    }

    //发送棋子数据信息
    async acceptChessData(data) {
        const list = this.userListObject[data.enemy];
        //如果对方在线则发送
        if (list && list.length > 0) {
            for (let i = 0; i < list.length; i++) {
                list[i].emit('acceptChessData', data);
            }
        }
    }

    //发送消息给同一浏览器的不同标签页
    async sendToOther(id, socket, data) {
        const list = this.userListObject[id];
        //如果对方在线则发送
        if (list && list.length > 0) {
            for (let i = 0; i < list.length; i++) {
                list[i].emit('successAddMessage', data);
                //通知用户更新聊天列表
                await CustomSocket.getChatList(id, list[i]);
            }
        }
    }

    //发送消息给对方
    async sendMessageToOther(fromUserId, toUserId, message) {
        const list = this.userListObject[toUserId];
        //如果对方在线则发送
        if (list && list.length > 0) {
            for (let i = 0; i < list.length; i++) {
                if (list[i]['isChat']) {
                    list[i].emit('acceptMessage', message);
                } else {
                    await CustomSocket.getNewMessageCount(toUserId, list[i]);
                    await CustomSocket.getChatList(toUserId, list[i]);
                }
                list[i].emit('newMessageSound');
            }
        }
    }

    //发消息
    async sendMessage(toUserId, event, data = {}) {
        const list = this.userListObject[toUserId];
        //如果对方在线则发送
        if (list && list.length > 0) {
            for (let i = 0; i < list.length; i++) {
                list[i].emit(event, data);
            }
        }
    }

    //通知对方已接收消息
    async messageIsRead(fromUserId, toUserId) {
        const list = this.userListObject[toUserId];
        //如果对方在线则发送
        if (list && list.length > 0) {
            for (let i = 0; i < list.length; i++) {
                list[i].emit('messageIsRead', {fromUserId, toUserId});
            }
        }
    }

    //添加到用户对象
    addToUserListObject(id, socket) {
        if (this.userListObject[id]) {
            if (!this.userListObject[id].includes(socket)) {
                this.userListObject[id].push(socket);
            }
        } else {
            this.userListObject[id] = [socket];
        }
        this.checkOnlineUser(socket);
    }

    //从用户对象移除
    removeFromUserListObject(id, socket) {
        if (this.userListObject[id]) {
            let index = this.userListObject[id].indexOf(socket);
            if (index > -1) {
                this.userListObject[id].splice(index, 1);
            }
            if (this.userListObject[id].length === 0) {
                delete this.userListObject[id];
            }
        }
        this.checkOnlineUser(socket);
    }

    //返回未读消息数
    static async getNewMessageCount(id, socket) {
        const count = await getNewMessageCount(id);
        socket.emit('newMessageCount', count);
    }

    //获取当前用户聊天列表
    static async getChatList(id, socket) {
        const data = await getChatList({id});
        socket.emit('chatList', data.data.list);
    }

    //判断用户是否退出登录
    async logout(id, socket) {

    }

    //用户是否在线
    async isOnline(id) {
        return this.userListObject[id];
    }
}

module.exports = CustomSocket;